package com.sheng.leetcode.year2022.month07.day15;

import org.junit.Test;

/**
 * @author liusheng
 * @date 2022/07/15
 *
 * 558. 四叉树交集
 *
 * 二进制矩阵中的所有元素不是 0 就是 1 。
 * 给你两个四叉树，quadTree1 和 quadTree2。其中 quadTree1 表示一个 n * n 二进制矩阵，
 * 而 quadTree2 表示另一个 n * n 二进制矩阵。
 * 请你返回一个表示 n * n 二进制矩阵的四叉树，它是 quadTree1 和 quadTree2 所表示的两个二进制矩阵进行 按位逻辑或运算 的结果。
 * 注意，当 isLeaf 为 False 时，你可以把 True 或者 False 赋值给节点，两种值都会被判题机制 接受 。
 * 四叉树数据结构中，每个内部节点只有四个子节点。此外，每个节点都有两个属性：
 * val：储存叶子结点所代表的区域的值。1 对应 True，0 对应 False；
 * isLeaf: 当这个节点是一个叶子结点时为 True，如果它有 4 个子节点则为 False 。
 * class Node {
 *     public boolean val;
 *     public boolean isLeaf;
 *     public Node topLeft;
 *     public Node topRight;
 *     public Node bottomLeft;
 *     public Node bottomRight;
 * }
 * 我们可以按以下步骤为二维区域构建四叉树：
 *
 * 如果当前网格的值相同（即，全为 0 或者全为 1），将 isLeaf 设为 True ，将 val 设为网格相应的值，并将四个子节点都设为 Null 然后停止。
 * 如果当前网格的值不同，将 isLeaf 设为 False， 将 val 设为任意值，然后如下图所示，将当前网格划分为四个子网格。
 * 使用适当的子网格递归每个子节点。
 *
 * 如果你想了解更多关于四叉树的内容，可以参考 wiki 。
 * 四叉树格式：
 * 输出为使用层序遍历后四叉树的序列化形式，其中 null 表示路径终止符，其下面不存在节点。
 * 它与二叉树的序列化非常相似。唯一的区别是节点以列表形式表示 [isLeaf, val] 。
 * 如果 isLeaf 或者 val 的值为 True ，则表示它在列表 [isLeaf, val] 中的值为 1 ；
 * 如果 isLeaf 或者 val 的值为 False ，则表示值为 0 。
 *
 * 示例 1：
 * 输入：quadTree1 = [[0,1],[1,1],[1,1],[1,0],[1,0]]
 * , quadTree2 = [[0,1],[1,1],[0,1],[1,1],[1,0],null,null,null,null,[1,0],[1,0],[1,1],[1,1]]
 * 输出：[[0,0],[1,1],[1,1],[1,1],[1,0]]
 * 解释：quadTree1 和 quadTree2 如上所示。由四叉树所表示的二进制矩阵也已经给出。
 * 如果我们对这两个矩阵进行按位逻辑或运算，则可以得到下面的二进制矩阵，由一个作为结果的四叉树表示。
 * 注意，我们展示的二进制矩阵仅仅是为了更好地说明题意，你无需构造二进制矩阵来获得结果四叉树。
 *
 * 示例 2：
 * 输入：quadTree1 = [[1,0]]
 * , quadTree2 = [[1,0]]
 * 输出：[[1,0]]
 * 解释：两个数所表示的矩阵大小都为 1*1，值全为 0
 * 结果矩阵大小为 1*1，值全为 0 。
 *
 * 示例 3：
 * 输入：quadTree1 = [[0,0],[1,0],[1,0],[1,1],[1,1]]
 * , quadTree2 = [[0,0],[1,1],[1,1],[1,0],[1,1]]
 * 输出：[[1,1]]
 *
 * 示例 4：
 * 输入：quadTree1 = [[0,0],[1,1],[1,0],[1,1],[1,1]]
 * , quadTree2 = [[0,0],[1,1],[0,1],[1,1],[1,1],null,null,null,null,[1,1],[1,0],[1,0],[1,1]]
 * 输出：[[0,0],[1,1],[0,1],[1,1],[1,1],null,null,null,null,[1,1],[1,0],[1,0],[1,1]]
 *
 * 示例 5：
 * 输入：quadTree1 = [[0,1],[1,0],[0,1],[1,1],[1,0],null,null,null,null,[1,0],[1,0],[1,1],[1,1]]
 * , quadTree2 = [[0,1],[0,1],[1,0],[1,1],[1,0],[1,0],[1,0],[1,1],[1,1]]
 * 输出：[[0,0],[0,1],[0,1],[1,1],[1,0],[1,0],[1,0],[1,1],[1,1],[1,0],[1,0],[1,1],[1,1]]
 *
 * 提示：
 * quadTree1 和 quadTree2 都是符合题目要求的四叉树，每个都代表一个 n * n 的矩阵。
 * n == 2^x ，其中 0 <= x <= 9.
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode.cn/problems/logical-or-of-two-binary-grids-represented-as-quad-trees
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
public class LeetCode0558 {

    @Test
    public void test01() {
        Node tl1 = new Node(true, true);
        Node tr1 = new Node(true, true);
        Node bl1 = new Node(false, true);
        Node br1 = new Node(false, true);
        Node quadTree1 = new Node(true, false, tl1, tr1, bl1, br1);

        Node tl2 = new Node(true, true);

        Node tl22 = new Node(false, true);
        Node tr22 = new Node(false, true);
        Node bl22 = new Node(true, true);
        Node br22 = new Node(true, true);
        Node tr2 = new Node(true, false, tl22, tr22, bl22, br22);

        Node bl2 = new Node(true, true);
        Node br2 = new Node(false, true);
        Node quadTree2 = new Node(true, false, tl2, tr2, bl2, br2);
        Node intersect = new Solution().intersect(quadTree1, quadTree2);
        System.out.println(intersect);
    }

}
// Definition for a QuadTree node.
class Node {
    public boolean val;
    public boolean isLeaf;
    public Node topLeft;
    public Node topRight;
    public Node bottomLeft;
    public Node bottomRight;

    public Node() {}

    public Node(boolean _val,boolean _isLeaf) {
        val = _val;
        isLeaf = _isLeaf;
    }

    public Node(boolean _val,boolean _isLeaf,Node _topLeft,Node _topRight,Node _bottomLeft,Node _bottomRight) {
        val = _val;
        isLeaf = _isLeaf;
        topLeft = _topLeft;
        topRight = _topRight;
        bottomLeft = _bottomLeft;
        bottomRight = _bottomRight;
    }
};

//class Solution {
//    public Node intersect(Node quadTree1, Node quadTree2) {
//        return null;
//    }
//}

//为了方便，我们令 quadTree1 为 t1，令 quadTree2 为 t2。
//根据题意，并利用给定函数作为递归函数，当 t1 和 t2 均为叶子节点数时，执行「或逻辑」，
//即若 t1 和 t2 任一值为 1 时，返回该节点，否则（两者均为 0），返回任一节点。
//然后考虑其他情况下，如何使用 t1 和 t2 构造新节点 ans，
//分别使用对应位置的进行「递归」构造即可（即使用 t1.topLeft 和 t2.topLeft 来赋值给 ans.topLeft，其余位置同理），
//要注意可能存在 t1 或 t2 其中一节点为叶子节点的情况，此时应当使用当前叶子节点和另一节点的子节点进行构造。
//最后考虑什么情况下，会产生新的叶子节点：若当前节点 ans 的四个子节点均为叶子节点，
//并且值相同时，ans 会成为叶子节点，ans 值为叶子节点的值，
//此时需要执行的操作为将 isLeaf 设定为 True，修改 val 为原子节点的值，将四个原子节点置空。
//
class Solution {
    public Node intersect(Node t1, Node t2) {
        //如果t1和t2的isLeaf都为true，代表为叶子节点，并且当前结点全为0或1
        if (t1.isLeaf && t2.isLeaf) {
            //有一个val为1，则返回1
            if (t1.val) {
                return t1;
            } else if (t2.val) {
                return t2;
            } else {
                //两个val都不为1，则随机返回任一个
                return t1;
            }
        }
        //返回的四叉树ans
        Node ans = new Node();
        //对4个部分分别进行递归，判断t1或t2其中一个的结点为叶子结点的情况，使用当前叶子结点和另一结点的子节点进行构造
        //t1.isLeaf为true时，代表t1为叶子结点，没有子节点，直接传递t1；t2.isLeaf为true时，代表t2为叶子结点，没有子节点，直接传递t2
        ans.topLeft = intersect(t1.isLeaf ? t1 : t1.topLeft, t2.isLeaf ? t2 : t2.topLeft);
        ans.topRight = intersect(t1.isLeaf ? t1 : t1.topRight, t2.isLeaf ? t2 : t2.topRight);
        ans.bottomLeft = intersect(t1.isLeaf ? t1 : t1.bottomLeft, t2.isLeaf ? t2 : t2.bottomLeft);
        ans.bottomRight = intersect(t1.isLeaf ? t1 : t1.bottomRight, t2.isLeaf ? t2 : t2.bottomRight);
        //a为true时，代表当前ans的4个子节点均为叶子结点
        boolean a = ans.topLeft.isLeaf && ans.topRight.isLeaf && ans.bottomLeft.isLeaf && ans.bottomRight.isLeaf;
        //b为true，代表当前ans的4个子节点的值均为true
        boolean b = ans.topLeft.val && ans.topRight.val && ans.bottomLeft.val && ans.bottomRight.val;
        //c为false时，代表当前ans的4个子节点的值均为false
        boolean c = ans.topLeft.val || ans.topRight.val || ans.bottomLeft.val || ans.bottomRight.val;
        //a && (b || !c)判断当前ans的4个子节点均为叶子结点时，子节点的值是否都相同
        //如果ans的4个子节点都是叶子结点，并且值都相等，那么ans会成为叶子结点，ans的值为叶子结点的值
        //将isLeaf设置为true
        ans.isLeaf = a && (b || !c);
        //修改val为原来4个子节点对应的值
        ans.val = ans.topLeft.val;
        //并将4个原子节点置null（如果ans的val为true，代表没有子结点，4个子节点全部置为null）
        if (ans.isLeaf) {
            ans.topLeft = ans.topRight = ans.bottomLeft = ans.bottomRight = null;
        }
        //返回ans
        return ans;
    }
}
//
//作者：AC_OIer
//链接：https://leetcode.cn/problems/logical-or-of-two-binary-grids-represented-as-quad-trees/solution/by-ac_oier-2ri3/
//来源：力扣（LeetCode）
//著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
